package crmdna.client.practice;

import static crmdna.common.OfyService.ofy;

import java.util.ArrayList;
import java.util.List;

import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.googlecode.objectify.Key;

import crmdna.client.sequence.Sequence;
import crmdna.client.sequence.Sequence.SequenceType;
import crmdna.client.user.User;
import crmdna.client.user.User.Action;
import crmdna.client.user.User.ResourceType;
import crmdna.common.APIException;
import crmdna.common.APIResponse.Status;
import crmdna.crmdna.Client;

public class Practice {		
	public static class PracticeProp implements Comparable<PracticeProp>{
		public long practiceId;
		public String name;
		public String displayName;
		
		@Override
		public int compareTo(PracticeProp arg0) {			
			return name.compareTo(arg0.name);
		}		
	}
	
	public static PracticeProp create(String client, String displayName, String login) {
		
		Client.ensureValidClient(client);
		User.ensureAccess(client, login, ResourceType.PRACTICE, 0, Action.WRITE);
		
		String name = displayName.toLowerCase();
		
		List<Key<PracticeEntity>> keys = ofy(client).load()
				.type(PracticeEntity.class).filter("name", name).keys().list();
		
		if (keys.size() != 0)
			throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
					"There is already a practice with name [" + displayName + "]");
					
		String key = getUniqueKey(client, name);
		long val = MemcacheServiceFactory.getMemcacheService()
				.increment(key, 1, (long)0);
		
		if (val != 1)
			throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
					"There is already a group with name [" + displayName + "]");
		
		PracticeEntity entity = new PracticeEntity();		
		entity.practiceId = Sequence.getNext(client, SequenceType.PRACTICE);
		entity.name = name;
		entity.displayName = displayName;
		ofy(client).save().entity(entity).now();
		
		return entity.toProp();			
	}
	
	private static String getUniqueKey(String namespace, String name) {
		return namespace + "_" + SequenceType.PRACTICE + "_" + name;
 	}
	
	public static PracticeEntity safeGet(String client, long practiceId) {
		
		Client.ensureValidClient(client);
		
		PracticeEntity entity = ofy(client).load().type(PracticeEntity.class).id(practiceId).get();
		if (null == entity)
			throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
					"Practice [" + practiceId + "] does not exist");
		
		return entity;			
	}		
	
	public static PracticeProp rename(String client, long practiceId, String newDisplayName, String login) {
		Client.ensureValidClient(client);
		User.ensureAccess(client, login, ResourceType.PRACTICE, 0, Action.WRITE);
		
		PracticeEntity entity = safeGet(client, practiceId);
		
		String newName = newDisplayName.toLowerCase();
		
		if (entity.name.equals(newName)) {
			//ideally should be inside a transaction
			entity.displayName = newDisplayName;
			ofy(client).save().entity(entity).now();
			return entity.toProp();
		}
		
		List<Key<PracticeEntity>> keys = ofy(client).load()
				.type(PracticeEntity.class).filter("name", newName).keys().list();		
		if (keys.size() != 0)
			throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
					"There is already a practice with name [" + newDisplayName + "]");
		
		String key = getUniqueKey(client, newName);
		long val = MemcacheServiceFactory.getMemcacheService()
				.increment(key, 1, (long)0);
		
		if (val != 1)
			throw new APIException(Status.ERROR_RESOURCE_ALREADY_EXISTS, 
					"There is already a practice with name [" + newDisplayName + "]");
		
		//ideally should be inside a transaction
		entity.name = newName;
		entity.displayName = newDisplayName;
		ofy(client).save().entity(entity).now();
		
		return entity.toProp();		
	}
	
	public static List<PracticeProp> getAll(String client) {
		Client.ensureValidClient(client);
		
		List<PracticeEntity> entities = ofy(client).load().type(PracticeEntity.class).order("name").list();
		
		List<PracticeProp> props = new ArrayList<>();
		for (PracticeEntity entity : entities) 
			props.add(entity.toProp());
		
		return props;							
	}
	
	public static void delete(String client, long practiceId, String login) {
						
		Client.ensureValidClient(client);
		User.ensureAccess(client, login, ResourceType.PRACTICE, 0, Action.WRITE);
				
		//there should not be any program type referencing this		
		throw new APIException(Status.ERROR_NOT_IMPLEMENTED, "This functionality is not implemented yet");
	}		
}
